#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <cassert>
#include <fstream>
#include <memory>
#include "../comm/Log.hpp"
#include "../comm/util.hpp"
#include "database.hpp"

namespace ns_model
{
    using namespace ns_util;
    using namespace ns_database;

    struct Question
    {
        std::string show_num; // 显示编号
        std::string num;      // 题目编号
        std::string title;    // 题目标题
        std::string level;    // 题目难度等级
        int cpu_limit;        // 题目时间限制 单位 s
        int mem_limit;        // 题目内存限制 单板 byte
        std::string desc;     // 题目描述
        std::string header;   // 用户需要用到的头文件
        std::string body;     // 显示给用户的代码
        std::string tail;     // 用来测试用户的代码
    };

    class Model
    {
    public:
        Model()
            : _db(new DataBase)
        {
            assert(LoadConf());
        }
        bool LoadConf(int flag = false /**是否部分加载**/)
        {
            // select * from oj_questions limit _map.size(), 1;
            std::string sql = "select * from oj_questions";
            if (flag)
            {
                sql += " limit ";
                sql += std::to_string(_map.size());
                sql += ", 1;";
            }
            else
            {
                sql += ";";
            }
            MYSQL_RES *result = nullptr;
            if (!_db->QueryMysql(sql, result))
                return false;
            // 分析结果
            if (flag)
            {
                MYSQL_ROW line = mysql_fetch_row(result);
                _map.insert({line[0], std::to_string(_map.size() + 1)});
                return true;
            }
            int row = mysql_num_rows(result);
            // 获取内容
            for (int i = 0; i < row; ++i)
            {
                MYSQL_ROW line = mysql_fetch_row(result);
                _map.insert({line[0], std::to_string(i + 1)});
            }
            free(result);

            return true;
        }
        bool GetAllQuestions(std::vector<Question> &qs)
        {
            std::string sql = "select * from oj_questions;";
            return QueryMysql(sql, qs);
        }
        bool GetOneQuestionByNumber(const std::string &number, Question &question)
        {
            std::string sql = "select * from oj_questions where number=" + number + ";";
            std::vector<Question> v;
            if (QueryMysql(sql, v))
            {
                if (v.size() == 1)
                {
                    question = std::move(v[0]);
                    return true;
                }
            }
            return false;
        }
        bool QueryMysql(const std::string &sql, std::vector<Question> &qs)
        {
            MYSQL_RES *result = nullptr;
            if (!_db->QueryMysql(sql, result))
                return false;
            // 分析结果
            int row = mysql_num_rows(result);

            // 获取内容
            for (int i = 0; i < row; ++i)
            {
                MYSQL_ROW line = mysql_fetch_row(result);
                Question q;
                q.num = line[0];
                q.title = line[1];
                q.level = line[2];
                q.desc = line[3];
                q.header = line[4];
                q.body = line[5];
                q.tail = line[6];
                q.cpu_limit = atoi(line[7]);
                q.mem_limit = atoi(line[8]);
                q.show_num = _map[q.num];

                qs.push_back(std::move(q));
            }
            free(result);

            return true;
        }
        int SignIn(const std::string &in_json, const std::string table, std::string &out_json)
        {
            // 1.获取用户信息
            Json::Value in_value;
            Json::Reader reader;
            reader.parse(in_json, in_value);
            std::string user = in_value["user"].asString();
            std::string password = in_value["password"].asString();
            // 2.构建sql语句
            std::string sql = "select * from " + table + " where user='";
            sql += user + "';";
            std::string result;
            int user_id = _db->Select(sql, password, result);
            Json::Value out_value;
            out_value["result"] = result;
            Json::FastWriter writer;
            out_json = writer.write(out_value);
            // 3.判断用户的合法性
            if (user_id > 0)
            {
                LOG(INFO, "用户:" + user + " 登录成功");
            }
            else
            {
                if (result == "1")
                    LOG(INFO, "用户不存在");
                else if (result == "2")
                    LOG(INFO, "用户密码错误");
                else
                    LOG(WARNING, "数据库代码编写存在错误");
            }
            return user_id;
        }
        // 注册
        bool Register(const std::string &in_json, std::string &out_json)
        {
            // 1.获取用户信息
            Json::Value in_value;
            Json::Reader reader;
            reader.parse(in_json, in_value);
            std::string user = in_value["user"].asString();
            std::string password = in_value["password"].asString();
            // 2.构建sql语句
            std::string sql = "insert into user(user, password) values('";
            sql += user;
            sql += "','";
            sql += password + "');";
            // 3.判断用户的合法性
            Json::Value out_value;
            if (_db->Insert(sql))
            {
                out_value["result"] = "success";
                Json::FastWriter writer;
                out_json = writer.write(out_value);
                LOG(INFO, "账号:" + user + " 注册成功, 密码:" + password);
                return true;
            }
            else
            {
                out_value["result"] = "fail";
                Json::FastWriter writer;
                out_json = writer.write(out_value);
                LOG(INFO, "注册失败,用户已存在");
                return false;
            }
        }
        // 忘记密码
        bool Forget(const std::string &in_json, std::string &out_json)
        {
            // 1.获取用户信息
            Json::Value in_value;
            Json::Reader reader;
            reader.parse(in_json, in_value);
            std::string user = in_value["user"].asString();
            std::string password = in_value["password"].asString();
            // 2.构建sql语句
            std::string sql = "select * from user where user='";
            sql += user + "';";
            std::string result;
            // 先判断用户是否存在
            _db->Select(sql, password, result);

            bool ret = true;
            if (result == "1")
            {
                // 用户不存在
                LOG(INFO, "用户:" + user + "不存在");
                ret = false;
            }
            else if (result == "")
            {
                // 开发人员解决
                LOG(WARNING, "数据库代码编写存在错误");
                ret = false;
            }
            else
            {
                // 用户存在
                std::string sql = "update user set password='" + password + "' where user = '" + user + "';";
                result = "";
                if (_db->Update(sql, result))
                {
                    LOG(INFO, "用户:" + user + " 更新密码成功,密码:" + password);
                }
                else
                {
                    LOG(WARNING, "数据库代码编写存在错误");
                    ret = false; // 开发人员解决
                }
            }
            Json::Value out_value;
            out_value["result"] = result;
            Json::FastWriter writer;
            out_json = writer.write(out_value);

            return ret;
        }
        std::string GetUserName(int id, const std::string &strId, const std::string &table)
        {
            return _db->GetUserName(id, strId, table);
        }
        void AddQuestion(const std::string &in_json, std::string &out_json)
        {
            _db->AddQuestion(in_json, out_json);
            // 更新_map
            LoadConf(true);
        }

    private:
        std::shared_ptr<DataBase> _db;
        std::unordered_map<std::string, std::string> _map; // num和show_num的映射关系
        std::string _last_number;                          // _map中最后一个题目在数据库中的编号
    };
}